/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package iamutkarshtiwari.github.io.ananas.editimage.utils;

import ohos.agp.components.Component;
import ohos.agp.components.Component.TouchEventListener;
import ohos.agp.components.VelocityDetector;
import ohos.multimodalinput.event.TouchEvent;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;

/**
 * 用于修复ohos{@link TouchEvent}内的一些数据错误，并矫正由此产生的一些计算错误，如：使用{@link VelocityDetector}计算速度等。
 * 此类适用于单手指移动的情况，暂未适配多手指，也不适用于{@link TouchEvent#getPointerScreenPosition(int)}。
 * 在{@link TouchEventListener#onTouchEvent(Component, TouchEvent)}内调用{@link #correctY(TouchEvent)}即可。
 * 注意：请勿重复或在滑动过程中构造此对象，构造函数中使用了反射，可能会造成性能问题。
 */
public class TouchEventCompact {

    private Method method;
    private Field ohosField;

    private float downY;
    private boolean corrected = false;
    private float offsetY = 0;

    /**
     * 初始化
     */
    public TouchEventCompact() {
        try {
            Class<?> aClass = Class.forName("android.view.MotionEvent");
            for (Method declaredMethod : aClass.getDeclaredMethods()) {
                if (declaredMethod.getName().equals("offsetLocation")) {
                    declaredMethod.setAccessible(true);
                    method = declaredMethod;
                }
            }

            Class<?> impl = Class.forName("ohos.multimodalinput.eventimpl.TouchEventImpl");
            ohosField = impl.getDeclaredField("motionEvent");
            ohosField.setAccessible(true);

        } catch (ClassNotFoundException | NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

    /**
     * 修正{@link TouchEvent}的y轴偏移
     *
     * @param ev 待修正的TouchEvent
     */
    public void correctY(TouchEvent ev) {
        float positionY = getY(ev);
        switch (ev.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                downY = positionY;
                break;

            case TouchEvent.POINT_MOVE:
                if (!corrected) {
                    offsetY = BigDecimal.valueOf(downY).subtract(BigDecimal.valueOf(positionY)).floatValue();
                    corrected = true;
                }
                try {
                    Object mv = ohosField.get(ev);
                    method.invoke(mv, 0, offsetY);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
                break;

            case TouchEvent.PRIMARY_POINT_UP:
            case TouchEvent.CANCEL:
                recycle();
                break;

        }
    }

    /**
     * 重置
     */
    public void recycle() {
        downY = 0;
        corrected = false;
        offsetY = 0;
    }

    private float getY(TouchEvent ev) {
        return ev.getPointerPosition(0).getY();
    }

}
